﻿//////////////////////////////////////////////////////////////////////////////
//
// Copyright © 1998-2024 Glodon Company Limited.
//
// Licensed under the MIT License
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the “Software”),
// to deal in the Software without restriction, including without limitation
// the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
//////////////////////////////////////////////////////////////////////////////
#include "StructureSlopeLineBehaviors.h"
#include "AlgorithmProject.h"
#include "AuxiliaryElementUtils.h"
#include "DbObjectUtils.h"
#include "GbmpBuiltInParameterDefinitionsNew.h"
#include "GbmpCalculatorBase.h"
#include "GbmpModelViewTypes.h"
#include "GcmpBuiltInCategoryUniIdentities.h"
#include "ICalculatorCollection.h"
#include "ICopyStrategyReporter.h"
#include "IElementBasicInformation.h"
#include "IElementModelShape.h"
#include "IElementParentReporter.h"
#include "IElementPosition.h"
#include "IElementShapeHandle.h"
#include "IElementStatus.h"
#include "IGenericElement.h"
#include "IGraphicsElementShape.h"
#include "IGraphicsLine.h"
#include "IGraphicsPoint.h"
#include "IGraphicsStyleManager.h"
#include "IModelView.h"
#include "IParameter.h"
#include "IParameterDefinitionLibrary.h"
#include "IPlane.h"
#include "IRegenerator.h"
#include "IRegeneratorDataIdCreator.h"
#include "ParameterStorageType.h"
#include "StructureSlopeLine.h"
#include "Vector2dUtils.h"
#include "NdbUpgrade.h"
#include "EnableCompileWarning_The_LAST_IncludeInCpp.h"


using namespace gcmp;

//////////////////////////////////////////////////////////////////////////////////////////////////////

BEGIN_UPGRADE_CLASS(gcmp, StructureSlopeLineViewSpecificShapeComponent, 2)
ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IRenderPriorityOffsetProvider>, RenderPriorityOffsetProvider)
END_UPGRADE_CLASS

BEGIN_UPGRADE_CLASS(gcmp, StructureSlopeLineViewSpecificShapeComponent, 3)
ADD_OWNERPTR_IDB_PROPERTY(OwnerPtr<IGraphicsNodeVisibilityCustomizer>, GraphicsNodeVisibilityCustomizer)
END_UPGRADE_CLASS

DBOBJECT_DATA_DEFINE(StructureSlopeLineViewSpecificShapeComponent)
{
    m_pOwnerElement = nullptr;
    m_GraphicsNodeVisibilityCustomizer = nullptr;
}

bool StructureSlopeLineViewSpecificShapeComponent::SetOwnerElement(IElement* pOwnerElement)
{
    m_pOwnerElement = pOwnerElement;
    IGraphicsNodeVisibilityCustomizer* pCustomizer = m_GraphicsNodeVisibilityCustomizer.get();
    if (pCustomizer)
    {
        pCustomizer->SetOwnerElement(pOwnerElement);
    }
    return true;
}

bool StructureSlopeLineViewSpecificShapeComponent::IsVisibleInModelView(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    const IElement *pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElement, L"pOwnerElement为空",L"GDMPLab",L"2024-03-30");
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElement);
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine *pSlopeline = quick_cast<StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeline, L"pSlopeline为空",L"GDMPLab",L"2024-03-30");

    const IElementStatus* pStatus = pGenericElement->GetStatus();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pStatus, L"无法获取状态集",L"GDMPLab",L"2024-03-30");
    return pStatus->IsVisible();
}

OwnerPtr<IGraphicsElementShape> gcmp::StructureSlopeLineViewSpecificShapeComponent::CreateViewSpecificElementShape(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView, L"pModelView为空",L"GDMPLab",L"2024-03-30");
    const IElement *pOwnerElement = GetOwnerElement();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pOwnerElement, L"pOwnerElement为空",L"GDMPLab",L"2024-03-30");
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pOwnerElement);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine *pSlopeline = quick_cast<StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pSlopeline, L"pSlopeline为空",L"GDMPLab",L"2024-03-30");

    return pSlopeline->GetGraphicsLineAndArrow();
}

void gcmp::StructureSlopeLineViewSpecificShapeComponent::SetRenderPriorityOffsetProvider(OwnerPtr<IRenderPriorityOffsetProvider> opProvider)
{
    SetRenderPriorityOffsetProvider__(TransferOwnership(opProvider));
}

const IRenderPriorityOffsetProvider* gcmp::StructureSlopeLineViewSpecificShapeComponent::GetRenderPriorityOffsetProvider() const
{
    return GetRenderPriorityOffsetProvider__().get();
}

IRenderPriorityOffsetProvider* gcmp::StructureSlopeLineViewSpecificShapeComponent::GetRenderPriorityOffsetProvider()
{
    return GetRenderPriorityOffsetProviderFW__().get();
}

void StructureSlopeLineViewSpecificShapeComponent::SetGraphicsNodeVisibilityCustomizer(OwnerPtr<IGraphicsNodeVisibilityCustomizer> opCustomizer)
{
    if (opCustomizer)
    {
        opCustomizer->SetOwnerElement(GetOwnerElement());
    }
    SetGraphicsNodeVisibilityCustomizer__(TransferOwnership(opCustomizer));
}

const IGraphicsNodeVisibilityCustomizer* StructureSlopeLineViewSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer() const
{
    return GetGraphicsNodeVisibilityCustomizer__().get();
}

IGraphicsNodeVisibilityCustomizer* StructureSlopeLineViewSpecificShapeComponent::GetGraphicsNodeVisibilityCustomizer()
{
    return GetGraphicsNodeVisibilityCustomizerFW__().get();
}
//////////////////////////////////////////////////////////////////////////////////////////////////////

DBOBJECT_DATA_DEFINE(StructureSlopeLineTransformationComponent)
{
    m_pOwnerElement = nullptr;
}

bool StructureSlopeLineTransformationComponent::CanBeMoved(std::wstring* explanation/* = nullptr*/) const
{
    SAFE_INIT_POINTER(explanation, L"");

    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(m_pOwnerElement.Get());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = dynamic_cast<const StructureSlopeLine*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    return pGenericElement->GetStatus()->CanBeMoved();
}

bool StructureSlopeLineTransformationComponent::Translate(const IElementMoveContext& moveContext)
{
    Vector3d moveDir = moveContext.GetMoveVector();
    Matrix4d translationMat;
    translationMat.MakeTranslate(moveDir.X(), moveDir.Y(), moveDir.Z());
    return this->Transform(translationMat);
}

bool StructureSlopeLineTransformationComponent::CanBeRotated(std::wstring* explanation/* = nullptr*/) const
{
    SAFE_INIT_POINTER(explanation, L"");

    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = dynamic_cast<const StructureSlopeLine*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    return pGenericElement->GetStatus()->CanBeRotated();
}

bool StructureSlopeLineTransformationComponent::Rotate(const Vector3d& pointOnVec, const Vector3d& rotateDir, double rotateAngle)
{
    Matrix4d rotationMat;
    rotationMat.MakeRotate(pointOnVec, rotateDir, rotateAngle);
    return this->Transform(rotationMat);
}

bool StructureSlopeLineTransformationComponent::Transform(const Matrix4d& matrix)
{
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(const_cast<IElement*>(m_pOwnerElement.Get()));
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

    StructureSlopeLine* pSlopeLine = dynamic_cast<StructureSlopeLine*>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    IElement* pElement = pSlopeLine->GetOwnerElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElement, L"IElement为空",L"GDMPLab",L"2024-03-30");
    IElementPosition* pPositionBehavior = pElement->GetElementPosition();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pPositionBehavior, L"pPositionBehavior为空",L"GDMPLab",L"2024-03-30");

    IElementPositionPoints* pControlPointBehavior = pElement->GetPositionPoints();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pControlPointBehavior, L"pControlPointBehavior为空",L"GDMPLab",L"2024-03-30");
    for (int idx = 0; idx < pControlPointBehavior->GetControlPointCount(); ++idx)
    {
        pControlPointBehavior->MarkControlPointRdId(idx);
    }

    return pPositionBehavior->Transform(matrix);
}

//////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(StructureSlopeLineCopyPasteComponent)
{
    m_pOwnerElement = nullptr;
}

gcmp::StructureSlopeLineCopyPasteComponent::StructureSlopeLineCopyPasteComponent(IElement* pElement)
    : m_pOwnerElement(pElement)
{}

IDocument* StructureSlopeLineCopyPasteComponent::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId StructureSlopeLineCopyPasteComponent::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}

bool gcmp::StructureSlopeLineCopyPasteComponent::CanBeCopied(std::wstring* pErrorMessage) const
{
    SAFE_INIT_POINTER(pErrorMessage, GBMP_TR(L"楼板坡度线无法被复制。"));
    return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(StructureSlopeLineCopyStrategyComponent) {
    m_pOwnerElement = nullptr;
}

void gcmp::StructureSlopeLineCopyStrategyComponent::Report(const gcmp::ICopyContext & copyContext, gcmp::ICopyStrategyReporter & reporter) const
{
    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(GetDocument()->GetElement(this->GetOwnerElementId()));
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = quick_cast<StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    reporter.ReportToKeep(pSlopeLine->GetInstanceId());
}

IDocument * gcmp::StructureSlopeLineCopyStrategyComponent::GetDocument() const
{
    return this->GetOwnerElement()->GetDocument();
}

ElementId gcmp::StructureSlopeLineCopyStrategyComponent::GetOwnerElementId() const
{
    return GetOwnerElement()->GetElementId();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(StructureSlopeLineParametersCustomizer)
{
    SetOwnerElement(nullptr);
}

OwnerPtr<IParameter> StructureSlopeLineParametersCustomizer::GetNativeParameter(int paramDefId) const
{
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, nullptr, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = quick_cast<const StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pSlopeLine, nullptr, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IParameter> param;
    ParameterAttributes pa = {false, false, true};
    // 坡度定义方式
    if (paramDefId == PARAMETER_ID(FloorSlopeDefinitionTypeBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Int, false, false,
            //true, PARAMETER_UID(FloorSlopeDefinitionTypeBuiltInParameter), ParameterProcessType::GeneralInput);
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Int, pa,
            PARAMETER_UID(FloorSlopeDefinitionTypeBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsInt(static_cast<int>(pSlopeLine->GetSlopeDefinitionType()));
        return TransferOwnership(param);
    }
    // 坡度箭头起点偏移
    else if (paramDefId == PARAMETER_ID(FloorSlopeStartOffsetBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Double, false, false,
            //true, PARAMETER_UID(FloorSlopeStartOffsetBuiltInParameter), ParameterProcessType::GeneralInput);
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Double, pa,
            PARAMETER_UID(FloorSlopeStartOffsetBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsDouble(pSlopeLine->GetStartElevationOffset());
        return TransferOwnership(param);
    }
    // 坡度箭头终点偏移
    else if (paramDefId == PARAMETER_ID(FloorSlopeEndOffsetBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Double, false, false,
            //true, PARAMETER_UID(FloorSlopeEndOffsetBuiltInParameter), ParameterProcessType::GeneralInput);
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Double, pa,
            PARAMETER_UID(FloorSlopeEndOffsetBuiltInParameter), ParameterProcessType::GeneralInput);
        param->SetValueAsDouble(pSlopeLine->GetEndElevationOffset());
        return TransferOwnership(param);
    }
    // 坡角
    else if (paramDefId == PARAMETER_ID(FloorSlopeAngleValueBuiltInParameter))
    {
        //param = NEW_AS_OWNER_PTR(Parameter, GetDocument(), ParameterStorageType::Double, false, false,
            //true, PARAMETER_UID(FloorSlopeAngleValueBuiltInParameter), ParameterProcessType::GeneralInput);
        param = IParameter::CreateParameter(GetDocument(), ParameterStorageType::Double, pa,
            PARAMETER_UID(FloorSlopeAngleValueBuiltInParameter), ParameterProcessType::GeneralInput);
        double slopeRad = pSlopeLine->GetSlopeAngle();
        param->SetValueAsDouble(slopeRad);
        return TransferOwnership(param);
    }

    return nullptr;
}

bool StructureSlopeLineParametersCustomizer::SetNativeParameter(const IParameter *param, 
    std::wstring* errorMsg)
{
    DBG_WARN_AND_RETURN_FALSE_UNLESS(param, L"param is null.",L"GDMPLab",L"2024-03-30");

    if (errorMsg)
    {
        errorMsg->clear();
    }

    IGenericElement* pGenericElement = quick_cast<IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    StructureSlopeLine* pSlope = quick_cast<StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlope, L"pSlope为空",L"GDMPLab",L"2024-03-30");

    // 坡度定义方式
    if (param->GetParameterDefinitionId() == PARAMETER_ID(FloorSlopeDefinitionTypeBuiltInParameter))
    {
        StructureSlopeDefinitionType slopeType = 
            static_cast<StructureSlopeDefinitionType>(param->GetValueAsInt());
        pSlope->SetSlopeDefinitionType(slopeType);
        return true;
    }
    // 坡度箭头起点偏移
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(FloorSlopeStartOffsetBuiltInParameter))
    {
        double startOffset = param->GetValueAsDouble();
        pSlope->SetStartElevationOffset(startOffset);
        return true;
    }
    // 坡度箭头终点偏移
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(FloorSlopeEndOffsetBuiltInParameter))
    {
        double endOffset = param->GetValueAsDouble();
        pSlope->SetEndElevationOffset(endOffset);
        return true;
    }
    // 坡角
    else if (param->GetParameterDefinitionId() == PARAMETER_ID(FloorSlopeAngleValueBuiltInParameter))
    {
        double slopeRad = param->GetValueAsDouble();
        double slopeAng = MathUtils::RadiansToAngle(slopeRad);
        if (false == Intervald(-89.99, 89.99).Contain(slopeAng))
        {
            SAFE_INIT_POINTER(errorMsg, GBMP_TR(L"坡度值范围应在[-89.99, 89.99]之间。"));
            return false;
        }

        double slopeHorizontalLength = Vector2dUtils::Distance(pSlope->GetStart().Vec2d(), pSlope->GetEnd().Vec2d());
        double trans = slopeHorizontalLength * std::tan(slopeRad);
        double endOffset = pSlope->GetStartElevationOffset() + trans;
        pSlope->SetEndElevationOffset(endOffset);
        return true;
    }

    return true;
}

void StructureSlopeLineParametersCustomizer::ReportParameterDefinitions(std::vector<int>* pParamDefIds) const
{
    DBG_WARN_AND_RETURN_VOID_UNLESS(pParamDefIds != nullptr, L"pParamDefUids为空",L"GDMPLab",L"2024-03-30");
    // 坡度定义方式
    pParamDefIds->push_back(PARAMETER_ID(FloorSlopeDefinitionTypeBuiltInParameter));
    // 坡度箭头起点偏移
    pParamDefIds->push_back(PARAMETER_ID(FloorSlopeStartOffsetBuiltInParameter));
    // 坡度箭头终点偏移
    pParamDefIds->push_back(PARAMETER_ID(FloorSlopeEndOffsetBuiltInParameter));
    // 坡角
    pParamDefIds->push_back(PARAMETER_ID(FloorSlopeAngleValueBuiltInParameter));
}

bool gcmp::StructureSlopeLineParametersCustomizer::IsParameterModifiable(int parameterId) const
{
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = quick_cast<const StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    StructureSlopeDefinitionType slopeType = pSlopeLine->GetSlopeDefinitionType();
    switch (slopeType)
    {
    case gcmp::StructureSlopeDefinitionType::ElevationDifference:
        if (PARAMETER_ID(FloorSlopeAngleValueBuiltInParameter) == parameterId)
        {
            return false;
        }
        break;
    case gcmp::StructureSlopeDefinitionType::SlopeAngle:
        if (PARAMETER_ID(FloorSlopeEndOffsetBuiltInParameter) == parameterId)
        {
            return false;
        }
        break;
    default:
        break;
    }

    return true;
}

IDocument * gcmp::StructureSlopeLineParametersCustomizer::GetDocument() const
{
    if (!m_pOwnerElement)
    {
        return nullptr;
    }
    return m_pOwnerElement->GetDocument();
}

ElementId gcmp::StructureSlopeLineParametersCustomizer::GetOwnerElementId() const
{
    if (!m_pOwnerElement)
    {
        return ElementId::InvalidID;
    }
    return m_pOwnerElement->GetElementId();
}
 

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(StructureSlopeLinePositionPoints)
{
    m_pOwnerElement = nullptr;
}

StructureSlopeLinePositionPoints::StructureSlopeLinePositionPoints(IElement* pOwnerElement) 
    : m_pOwnerElement(pOwnerElement)
{
}

int gcmp::StructureSlopeLinePositionPoints::GetControlPointCount() const
{
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, 0, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = quick_cast<const StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pSlopeLine, 0, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");
    const IElement* pElement = pSlopeLine->GetOwnerElement();
    DBG_WARN_AND_RETURN_UNLESS(pElement, 0, L"IElement为空",L"GDMPLab",L"2024-03-30");
    const IElementPosition* pPositionBehavior = pElement->GetElementPosition();
    DBG_WARN_AND_RETURN_UNLESS(pPositionBehavior, 0, L"pPositionBehavior为空",L"GDMPLab",L"2024-03-30");

    return pPositionBehavior->GetControlPointCount();
}

Vector3d StructureSlopeLinePositionPoints::GetControlPoint(int pointIndex) const
{
    const IGenericElement* pGenericElement = quick_cast<const IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_UNLESS(pGenericElement, Vector3d::Zero, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLine* pSlopeLine = quick_cast<const StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_UNLESS(pSlopeLine, Vector3d::Zero, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");
    const IElement* pElement = pSlopeLine->GetOwnerElement();
    DBG_WARN_AND_RETURN_UNLESS(pElement, Vector3d::Zero, L"IElement为空",L"GDMPLab",L"2024-03-30");
    const IElementPosition* pPositionBehavior = pElement->GetElementPosition();
    DBG_WARN_AND_RETURN_UNLESS(pPositionBehavior, Vector3d::Zero, L"pPositionBehavior为空",L"GDMPLab",L"2024-03-30");

    return pPositionBehavior->GetPointByIndex(pointIndex);
}

void StructureSlopeLinePositionPoints::SetControlPoint(int pointIndex, const Vector3d& pos) 
{
    IGenericElement* pGenericElement = quick_cast<IGenericElement>(this->GetOwnerElement());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement, L"pGenericElement为空",L"GDMPLab",L"2024-03-30");

    StructureSlopeLine* pSlopeLine = quick_cast<StructureSlopeLine>(pGenericElement->GetExternalObject());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pSlopeLine, L"pSlopeLine为空",L"GDMPLab",L"2024-03-30");

    IElement* pElement = pSlopeLine->GetOwnerElement();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElement, L"IElement为空",L"GDMPLab",L"2024-03-30");
    IElementPosition* pPositionBehavior = pElement->GetElementPosition();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPositionBehavior, L"pPositionBehavior为空",L"GDMPLab",L"2024-03-30");

    // set new pos
    pPositionBehavior->SetPointByIndex(pointIndex, pos);

    // regenerate
    this->MarkControlPointRdId(pointIndex);
}

RegenDataId gcmp::StructureSlopeLinePositionPoints::GetControlPointRdId(int pointIndex) const
{
    return RegenDataId(GetOwnerElement()->GetBasicInformation()->GetElementId().AsInt64(), GetControlPointRegenDataName(), pointIndex);
}

void gcmp::StructureSlopeLinePositionPoints::MarkControlPointRdId(int pointIndex)
{
    GetDocument()->GetRegenerator()->MarkRegenDataId(GetControlPointRdId(pointIndex));
}

int gcmp::StructureSlopeLinePositionPoints::GetControlPointRegenDataName() const
{
    static int name = gcmp::IRegeneratorDataIdCreator::CreateRegenDataId(
        WSTRING_OF("StructureSlopeLinePositionPoints"), 
        WSTRING_OF("gbmp" + "StructureSlopeLinePositionPoints")
    );
    return name;
}

IDocument * gcmp::StructureSlopeLinePositionPoints::GetDocument() const
{
    return this->GetOwnerElement()->GetDocument();
}

ElementId gcmp::StructureSlopeLinePositionPoints::GetOwnerElementId() const
{
    return GetOwnerElement()->GetElementId();
}

///////////////////////////////////////////////////////////////////////////////////////////////////////
DBOBJECT_DATA_DEFINE(StructureSlopeLineUiManipulatorComponent)
{
    m_pOwnerElement = nullptr;
}

namespace gcmp
{
    // 夹点位置更新计算器
    class StructureSlopeLineGripPointPositionCalculator : public GbmpCalculatorBase
    {
        DECLARE_CALCULATOR(StructureSlopeLineGripPointPositionCalculator, IElementShapeHandle)
    public:
        StructureSlopeLineGripPointPositionCalculator(IDocument* pDoc, const RegenDataId& outputDataId) : GbmpCalculatorBase(pDoc, outputDataId) {}
        virtual void ReportInputDataIds(std::vector<RegenDataId>& dataIds) const override;
        virtual void Execute() override;
    };
}

#pragma region GripPointPositionCalculator
void StructureSlopeLineGripPointPositionCalculator::ReportInputDataIds(std::vector<RegenDataId>& dataIds) const
{
    IElementShapeHandle* pElementShapeHandle = GetElement<IElementShapeHandle>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    dataIds.push_back(pElementShapeHandle->GetMasterIdRdIdForBehavior());
    dataIds.push_back(pElementShapeHandle->GetShapeHandlePositionIndexInMasterElementRdId());

    IDocument* pDoc = pElementShapeHandle->GetDocument();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pDoc, L"invalid pDoc",L"GDMPLab",L"2024-03-30");
    IElement* pMasterElem = pDoc->GetElement(pElementShapeHandle->GetMasterId());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pMasterElem, L"invalid pMasterElement",L"GDMPLab",L"2024-03-30");
    const IElementModelShape* pElementShape = pMasterElem->GetElementModelShape();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShape, L"invalid pElementShape",L"GDMPLab",L"2024-03-30");
    dataIds.push_back(pElementShape->GetGraphicsElementShapeRdId());

    const IGenericElement* pGenericElement = quick_cast<IGenericElement>(pMasterElem);
    DBG_WARN_AND_RETURN_VOID_UNLESS(pGenericElement != nullptr, L"Invalid pGenericElement",L"GDMPLab",L"2024-03-30");
    const StructureSlopeLinePositionPoints* pPosPoints = quick_cast<StructureSlopeLinePositionPoints>(pGenericElement->GetPositionPoints());
    DBG_WARN_AND_RETURN_VOID_UNLESS(pPosPoints != nullptr, L"Invalid pPosPoints",L"GDMPLab",L"2024-03-30");
    dataIds.push_back(pPosPoints->GetControlPointRdId(pElementShapeHandle->GetPositionIndexInMasterElement()));
}

void StructureSlopeLineGripPointPositionCalculator::Execute()
{
    IElementShapeHandle* pElementShapeHandle = GetElement<IElementShapeHandle>();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    IElementShapeHandleBehavior* pElementShapeHandleBehavior = pElementShapeHandle->GetElementShapeHandleBehavior();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandleBehavior, L"invalid pElementShapeHandleBehavior为空",L"GDMPLab",L"2024-03-30");
    pElementShapeHandleBehavior->UpdatePosition();
}

#pragma endregion GripPointPositionCalculator

#pragma region GripPointBehavior
DBOBJECT_DATA_DEFINE(StructureSlopeLineGripPointBehavior)
{
    m_Document = nullptr;
}

StructureSlopeLineGripPointBehavior::StructureSlopeLineGripPointBehavior(IDocument* pDoc, const ElementId& modelViewId)
    :m_Document(pDoc), m_ModelViewId(modelViewId)
{

}

IElementShapeHandle* StructureSlopeLineGripPointBehavior::GetElementShapeHandle() const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_Document, L"invalid pDocument",L"GDMPLab",L"2024-03-30");
    return quick_cast<IElementShapeHandle>(m_Document->GetElement(m_ElementShapeHandleId));
}

IElement* StructureSlopeLineGripPointBehavior::GetMasterElement() const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(m_Document, L"invalid pDocument",L"GDMPLab",L"2024-03-30");

    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementShapeHandle, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    return m_Document->GetElement(pElementShapeHandle->GetMasterId());
}

OwnerPtr<IElementShapeHandleBehavior> StructureSlopeLineGripPointBehavior::Create(IDocument* pDoc, const ElementId& modelViewId)
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pDoc && modelViewId.IsValid(), L"invalid parameter",L"GDMPLab",L"2024-03-30");
    return NEW_AS_OWNER_PTR(StructureSlopeLineGripPointBehavior, pDoc, modelViewId);
}

IMPLEMENT_CALCULATOR_CREATOR(gcmp, StructureSlopeLineGripPointPositionCalculator)
void StructureSlopeLineGripPointBehavior::GetCalculators(ICalculatorCollection* calculators) const
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    ADD_CALCULATOR(StructureSlopeLineGripPointPositionCalculator, pElementShapeHandle->GetDocument(), pElementShapeHandle->GetPositionRdIdForBehavior());
}

bool StructureSlopeLineGripPointBehavior::Translate(const IElementMoveContext& moveContext)
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pElementShapeHandle != nullptr, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    IElement* pOwnerElement = GetMasterElement();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElement, L"invalid pOwnerElement",L"GDMPLab",L"2024-03-30");

    IElementPositionPoints* pOwnerElementPosPoint = pOwnerElement->GetPositionPoints();
    DBG_WARN_AND_RETURN_FALSE_UNLESS(pOwnerElementPosPoint, L"invalid pOwnerElementPosPoint",L"GDMPLab",L"2024-03-30");

    int positionIndex = pElementShapeHandle->GetPositionIndexInMasterElement();

    Vector3d pos = pOwnerElementPosPoint->GetControlPoint(positionIndex);
    pOwnerElementPosPoint->SetControlPoint(positionIndex, pos + moveContext.GetMoveVector());

    //触发所有辅助对象关联更新
    std::vector<ElementId> vecGripPointIds = AuxiliaryElementUtils::GetAuxiliaryElements(pOwnerElement);
    return pOwnerElement->GetDocument()->GetRegenerator()->ForceRegeneratingElements(vecGripPointIds);
}

OwnerPtr<IGraphicsElementShape> StructureSlopeLineGripPointBehavior::CreateGrahicsElementShapeInModelView(const IModelView* pModelView) const
{
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pModelView != nullptr, L"invalid pModelView",L"GDMPLab",L"2024-03-30");

    if (PlanViewType != pModelView->GetUserDataId())

        return nullptr;

    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(pElementShapeHandle != nullptr, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    OwnerPtr<IPlane> opWorkPlane = pModelView->GetWorkPlane();
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opWorkPlane != nullptr, L"invalid opWorkPlane",L"GDMPLab",L"2024-03-30");

    // 更新GRep
    OwnerPtr<IGraphicsElementShape> opGGrepNodeRoot = IGraphicsElementShape::Create(GraphicsRenderLayer::TransientObject);
    DBG_WARN_AND_RETURN_NULLPTR_UNLESS(opGGrepNodeRoot != nullptr, L"invalid opGGrepNodeRoot",L"GDMPLab",L"2024-03-30");

    Vector2d uvParameter;
    Vector3d position;
    AlgorithmProject::Project(pElementShapeHandle->GetPosition(), opWorkPlane.get(), uvParameter, position);

    OwnerPtr<IGraphicsPoint> opPoint = IGraphicsPoint::Create(position);
    opPoint->SetDisplayShape(PointDisplayShapeType::Circle);
    opGGrepNodeRoot->AddChild(TransferOwnership(opPoint));
    opGGrepNodeRoot->SetElementId(pElementShapeHandle->GetElementId());
    opGGrepNodeRoot->SetIsClippable(false);

    // 设置属性
    IGraphicsStyleManager* pStyleManager = GetDocument()->GetGraphicsStyleManager();
    if (pStyleManager)
    {
        ElementId gstyleId = pStyleManager->GetGraphicsStyleIdByCategoryUid(BuiltInCategoryUniIdentities::BICU_AUXILIARY_ELEMENT);
        opGGrepNodeRoot->SetGraphicsStyleId(gstyleId);
    }

    return opGGrepNodeRoot;
}

void StructureSlopeLineGripPointBehavior::ReportParents(IElementParentReporter& reporter) const
{
    reporter.ReportWeak(GetModelViewId());
}

void StructureSlopeLineGripPointBehavior::UpdatePosition()
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");

    const IElement* pOwnerElement = GetMasterElement();

    //注：这里必须调用const版本的pOwnerElement，否则会引起事务外修改Element的DBG_WARN
    const IElementPositionPoints* pPositionPoints = pOwnerElement->GetPositionPoints();
    if (pPositionPoints)
    {
        int positionIndex = pElementShapeHandle->GetPositionIndexInMasterElement();
        Vector3d pos = pPositionPoints->GetControlPoint(positionIndex);
        pElementShapeHandle->SetPosition(pos);
    }
}

void StructureSlopeLineGripPointBehavior::GetNearestPoint(Vector3d& nearPoint) const
{
    IElementShapeHandle* pElementShapeHandle = GetElementShapeHandle();
    DBG_WARN_AND_RETURN_VOID_UNLESS(pElementShapeHandle != nullptr, L"invalid pElementShapeHandle",L"GDMPLab",L"2024-03-30");
    nearPoint = pElementShapeHandle->GetPosition();
}

bool StructureSlopeLineGripPointBehavior::GetHandleCommandString(const IObject* commandEnvironment, std::wstring& commandStr, CommandParameters& cmdParams) const
{
    return false;
}
#pragma endregion GripPointBehavior
